#!/usr/bin/python
# -*- coding: utf-8 -*-


import BasicHTTPServiceAPI.BasicHTTPService
import oauth

from error import APIError
from utils import convert_to_utf8_str


def bind_api(**config):
    """function for binding api method"""
    class APIMethod(object):
        """class for representing a api method"""
        url = config.get('url')
        method = config.get('method', 'GET')
        allowed_params = config.get('allowed_params', [])
        additional_params = config.get('additional_params', None)
        rest_params = config.get('rest_params', None) 
        require_auth = config.get('require_auth', False)
        SSL = config.get('ssl', False)
        data_type = config.get('data_type', None)
        data_format = config.get('data_format', 'json')
        data_list = config.get('data_list', False)
        multipart_form = config.get('multipart_form', False)

        def __init__(self, api, args, kargs):
            """constructor for APIMethod"""
            self.api = api
            self.params = self.build_params(args, kargs)
            tempbaseUrl = ''
            if self.SSL:
                tempbaseUrl += 'https://'
            else:
                tempbaseUrl += 'http://'
            self.baseUrl = tempbaseUrl + self.api.host + self.url
            if self.rest_params is not None:
                self.build_rest_params(args, kargs)
            if self.require_auth:
                self.params.update(self.build_oauth())
                self.sign_request()
            if self.additional_params:
                self.params.update(self.build_additional_params(args,\
                                                                kargs))

        def build_params(self, args, kargs):
            """build params for api method"""
            params = {}
            for idx, value in enumerate(args):
                try:
                    if type(value) is dict:
                        params.update(value)
                    else:
                        params[self.allowed_params[idx]] = \
                                convert_to_utf8_str(value)
                except IndexError:
                    raise APIError('Too many parameters supplied!')
            for k, v in kargs.items():
                if v is None:
                    continue
                if k in params:
                    raise APIError('multiple parameters for %s \
                                   are supplied!' % k)
                if k in self.allowed_params:
                    params[k] = convert_to_utf8_str(v)
            return params

        def build_rest_params(self, args, kargs):
            """build rest params"""
            for k, v in kargs.items():
                if v is None:
                    continue
                if k in self.rest_params:
                    tempBaseUrl = self.baseUrl.rsplit('.', 1)
                    tempUrl = self.url.rsplit('.', 1)
                    self.baseUrl = tempBaseUrl[0] + '/' + str(v) \
                            + '.' + tempBaseUrl[1] 
                    self.url = tempUrl[0] + '/' + str(v) \
                            + '.' + tempUrl[1] 


        def build_additional_params(self, args, kargs):
            """
            build additional params which is not included in the 
            signature string
            """
            params = {}
            for k, v in kargs.items():
                if v is None:
                    continue
                if k in params:
                    raise APIError('multiple parameters for %s are \
                                   supplied!' % k)
                if k in self.additional_params:
                    params[k] = open(v, 'rb')  
                    # additional_params is a filename
            return params


        def build_oauth(self):
            """build oauth params for api method"""
            oauth_params = {}
            oauth_params['oauth_consumer_key'] = \
                    convert_to_utf8_str(self.api.consumer.key)
            oauth_params['oauth_nonce'] = \
                    convert_to_utf8_str(oauth.generate_nonce(32))
            oauth_params['oauth_timestamp'] = \
                    convert_to_utf8_str(oauth.generate_timestamp())
            if self.api.access_token:
                oauth_params['oauth_token'] = \
                        convert_to_utf8_str(self.api.access_token.key)
            oauth_params['oauth_version'] = \
                    convert_to_utf8_str('1.0')
            return oauth_params

        def sign_request(self):
            """sign the request with HMAC-SHA1"""
            tempRequest = oauth.OAuthRequest(self.method, self.baseUrl, \
                                            self.params)
            signMethod = oauth.OAuthSignatureMethod_HMAC_SHA1()
            tempRequest.sign_request(signMethod, self.api.consumer, \
                                    self.api.access_token)
            self.params = tempRequest.parameters

        def execute(self):
            """execute the api method"""
            # in the asynchronous mode return the APIMethod instance with request
            # information.
            #res = BasicHTTPServiceAPI.BasicHTTPService.basicAPIFetch( \
            #                         self.api.host, \
            #                         self.url, \
            #                         self.params, \
            #                         method=self.method, \
            #                         SSL=self.SSL, \
            #                         multipart=self.multipart_form \
            #                     )
            #if res['status'] < 400:
            #    return self.api.parser.parse(self, res['data'])
            #else:
            #    raise APIError(res['status'])
            return self

    def _call(api, *args, **kargs):
        """call api method"""
        method = APIMethod(api, args, kargs)
        return method.execute()

    return _call
